﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;

namespace DVK.SP2007.UniversalClient.DataAccess
{
    /// <summary>
    /// Universal Client Data Access object.
    /// </summary>
    public class UniversalClientDao : IDisposable
    {
        private string _connectionString;
        private UniversalClientDataContext _dataContext;

        /// <summary>
        /// Initializes a new instance of the <see cref="UniversalClientDao"/> class.
        /// </summary>
        /// <param name="connectionString">The UK database connection string.</param>
        public UniversalClientDao(string connectionString)
        {
            _connectionString = connectionString;
            _dataContext = new UniversalClientDataContext(_connectionString);
            _dataContext.CommandTimeout = 360;
        }

        /// <summary>
        /// Adds the message for sending to UK Database.
        /// </summary>
        /// <param name="dvkMessage">The DVK message.</param>
        public void AddMessage(IDvkMessage dvkMessage)
        {
            //gather recipients
            EntitySet<dhl_message_recipient> recipients = new EntitySet<dhl_message_recipient>();

            foreach (SenderReceiverInfo recipient in dvkMessage.DataXml.Transport.GetRecipients())
            {
                recipients.Add(
                        new dhl_message_recipient()
                        {
                            recipient_name =
                                ((recipient.Person == null || recipient.Person.Name == null) ? string.Empty : recipient.Person.Name),
                            recipient_person_code =
                                ((recipient.Person == null || recipient.Person.Code == null) ? string.Empty : recipient.Person.Code),
                            recipient_org_code = recipient.Organisation.Code,
                            recipient_org_name = recipient.Organisation.Name
                        }
                    );
            }

            //gather message data
            var dhlMessage = new dhl_message()
            {
                case_name = dvkMessage.CaseName,
                data = dvkMessage.DataXml.ToString(),
                dhl_folder_name = dvkMessage.FolderName,
                dhl_id = null,
                metaxml = (dvkMessage.MetaXml != null) ? dvkMessage.MetaXml.ToString() : null,
                title = dvkMessage.Title,
                unit_id = dvkMessage.UnitId.HasValue ? dvkMessage.UnitId.Value : 0,
                sender_org_name = dvkMessage.Sender.Organisation.Name,
                sender_org_code = dvkMessage.Sender.Organisation.Code,
                sender_name = dvkMessage.Sender.Person.Name,
                sender_person_code = dvkMessage.Sender.Person.Code,
                sending_date = dvkMessage.SendingDate,
                dhl_message_recipients = recipients,
                local_item_id = dvkMessage.LocalItemId,
                sending_status_id = (int)dvkMessage.SendingStatus,
                status_update_needed = (dvkMessage.StatusUpdateNeeded ? 1 : 0)
            };

            //Insert the new message
            _dataContext.dhl_messages.InsertOnSubmit(dhlMessage);
            _dataContext.SubmitChanges();

            //Map the message id back to update the item with the message id
            dvkMessage.Id = dhlMessage.dhl_message_id;
        }

        /// <summary>
        /// Updates the message local item reference in UK database.
        /// </summary>
        /// <param name="dvkMessage">The DVK message.</param>
        /// <param name="localItemId">The local item id.</param>
        public void UpdateMessageLocalItemReference(IDvkMessage dvkMessage, int localItemId)
        {
            try
            {
                dhl_message message = (from msg in _dataContext.dhl_messages
                                       where msg.dhl_message_id == dvkMessage.Id
                                       select msg).Single();
                message.local_item_id = localItemId;
                _dataContext.SubmitChanges();
            }
            catch (Exception exc)
            {
                throw new DvkException("UpdateMessageLocalItemReference: Query dident return any value or update failed. messageId=" + dvkMessage.Id, exc);
            }

        }

        /// <summary>
        /// Gets the incoming messages from UK database.
        /// </summary>
        /// <returns></returns>
        public IList<IDvkMessage> GetIncomingMessages()
        {
            var dhlMessageQuery = from dhlMessage in _dataContext.dhl_messages
                                  where dhlMessage.is_incoming == 1 && (dhlMessage.local_item_id == null || dhlMessage.local_item_id.Value == 0)
                                  select dhlMessage;

            IList<IDvkMessage> incomingMessages = new List<IDvkMessage>();

            foreach (var dhlMessage in dhlMessageQuery)
            {
                IDvkMessage message = DvkMessageFactory.CreateMessage(dhlMessage);

                incomingMessages.Add(message);
            }
            return incomingMessages;

        }

        /// <summary>
        /// Updates the sent message status in the UK Database.
        /// Marks the message for update if status is not Sent.
        /// </summary>
        /// <param name="messageId">The message id.</param>
        /// <param name="sendingStatus">The sending status.</param>
        public void UpdateSentMessageStatus(int messageId, out DvkSendingStatus sendingStatus, out DvkFault fault)
        {
            fault = null;

            var dhlMessage = (from message in _dataContext.dhl_messages
                              where message.dhl_message_id == messageId
                              select message).Single();

            sendingStatus = (DvkSendingStatus)dhlMessage.sending_status_id;

            if (sendingStatus == DvkSendingStatus.Sent)
            {
                dhlMessage.status_update_needed = 0;
            }
            else
            {
                dhlMessage.status_update_needed = 1;
            }

            if (!string.IsNullOrEmpty(dhlMessage.fault_code))
            {
                fault = new DvkFault(dhlMessage.fault_actor, dhlMessage.fault_code, dhlMessage.fault_string, dhlMessage.fault_detail);
            }

            _dataContext.SubmitChanges();
        }

        /// <summary>
        /// Gets the DVK organisations.
        /// </summary>
        /// <returns>list of organisations</returns>
        public List<dhl_organization> GetAllOrganisations()
        {
            return (from organisation in _dataContext.dhl_organizations
                    select organisation).ToList();
        }


        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            this._dataContext.Dispose();
        }

        #endregion
    }
}